package com.xjw.tool;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xjw.entity.ChessAi;
import com.xjw.entity.ChessGameInfo;
import com.xjw.entity.ChessPoint;
import com.xjw.entity.IntNum;
import com.xjw.mapper.ChessMapper;
import com.xjw.service.FiveChess;

import java.util.*;

/**
 * 分析威胁度
 *
 * @author 徐军文
 * @since 2021/11/4 22:30
 */
public class DgUtil {

    /**
     * 记录具有威胁的棋子(对于ai)
     */
    public static List<ChessPoint> chessPoints = new ArrayList<>(100);

    /**
     * 记录具有威胁的棋子(对于自己)
     */
    public static List<ChessPoint> chessPointList = new ArrayList<>(100);


    private static final Log LOG = LogFactory.get("dangours util:");

    public static void main(String[] args) {
        FiveChess fiveChess = new FiveChess(16, 16, 28.0);
        ChessMapper chessMapper = MybatisUtils.getMapper(ChessMapper.class);
        ChessGameInfo gameInfo = chessMapper.getLast2GameInfo(83);
        char[][] chess = ArrayUtil.intArrToChar(ArrayUtil.stringToArray(gameInfo.getMap(), 15,15));
        System.out.println(ArrayUtil.getAllChess(chess,'B'));
        fiveChess.setChess(chess);
        ChessPoint chessPoint = dgPoint(gameInfo.getChessX(),gameInfo.getChessY(),'B',fiveChess);
        System.out.println(chessPoint);
    }

    /**
     * 根据棋子的危险度下棋
     *
     * @return ChessPoint
     */
    public static ChessPoint dgPoint(int row, int col, char chessColor, FiveChess fiveChess){
        ChessPoint result = null;
        ChessAi chessAi = new ChessAi(row, col, chessColor, fiveChess);
        chessPoints.addAll(getAllDangerous(chessAi));

        // 重置棋子威胁度
        LOG.info("初始化ai防御库");
        initDans(chessPoints, fiveChess, chessAi);
        chessAi.setChessColor(ChessUtil.getOtherColor(chessColor));
        LOG.info("初始化ai攻击库");
        initDans(chessPointList, fiveChess, chessAi);

        if(chessPointList.size() > 0) {
            if(chessPoints.size() > 0 ) {
                ChessPoint defendP = chessPoints.get(chessPoints.size()-1);
                ChessPoint attctP = chessPointList.get(chessPointList.size() - 1);
                if(defendP.getDg() > attctP.getDg()){
                    LOG.info("防御落子");
                    result = chessPoints.remove(chessPoints.size() -1);
                } else {
                    LOG.info("攻击落子");
                    result =  chessPointList.remove(chessPointList.size() - 1);
                }
            } else {
                LOG.info("攻击落子");
                result =  chessPointList.remove(chessPointList.size() - 1);
            }
        } else if ( chessPoints.size() > 0 ) {
            LOG.info("防御落子");
            result = chessPoints.remove(chessPoints.size() -1);
        }
        Random rd = new Random();
        List<ChessPoint> randomChess = ChessUtil.getAroundChess(row, col, fiveChess);
        if(result == null) {
            LOG.info("随机落子");
            result = randomChess.get(rd.nextInt(randomChess.size()));
        }
        ChessAi chessAiSelf = new ChessAi(result.getPointX(), result.getPointY(), ChessUtil.getOtherColor(chessColor), fiveChess);
        chessPointList.addAll(getAllDangerous(chessAiSelf));
        return result;
    }

    public static List<ChessPoint> getAllDangerous(ChessAi chessAi){
        List<ChessPoint> chessPoints = rowJudge(chessAi);
        chessPoints.addAll(colJudge(chessAi));
        chessPoints.addAll(mainDiagonalJudge(chessAi));
        chessPoints.addAll(deputyDiagonalJudge(chessAi));
        return chessPoints;
    }

    private static int getDangerousValue(ChessAi chessAi){
        int dg = rowDg(chessAi);
        dg += colDg(chessAi);
        dg += mainDiagonalDg(chessAi);
        dg += deputyDiagonalDg(chessAi);
        return dg;
    }

    /**
     * 初始化威胁度
     *
     * @param chessPoints 所有具有威胁的棋子（包括之前的）
     * @param fiveChess 棋盘
     * @param chessAi 数据分析包
     */
    private static void initDans(List<ChessPoint> chessPoints, FiveChess fiveChess, ChessAi chessAi) {
        // 具有威胁的位置如果已经落子则移除
        for(int i = chessPoints.size()-1;i>=0;i--){
            if(fiveChess.getChess()[chessPoints.get(i).getPointX()][chessPoints.get(i).getPointY()] != 32){
                chessPoints.remove(i);
            }
        }
        // 重新统计威胁度
        for(ChessPoint chessPoint:chessPoints){
            chessAi.setPointX(chessPoint.getPointX());
            chessAi.setPointY(chessPoint.getPointY());
            chessAi.setChessPoint(chessPoint);
            chessPoint.setDg(0);
            chessPoint.setDg(getDangerousValue(chessAi));
        }
        chessPoints.sort(Comparator.comparingInt(ChessPoint::getDg));
        LOG.info(Arrays.toString(chessPoints.toArray()));
    }

    /**
     * 行具有威胁的棋子判断
     *
     * @param chessAi 棋子分析数据包
     * @return 具有威胁的棋子
     */
    private static List<ChessPoint> rowJudge(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        int flag = 0;
        IntNum space = new IntNum(0);
        for (int j = chessAi.getPointY(); j <= chessAi.getFiveChess().getWidth() - 1; j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),chessAi.getPointX(),j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2) {
                break;
            }
            if(value == 3) {
                flag++;
                break;
            }
        }

        space.setNum(0);
        for (int j = chessAi.getPointY() - 1; j >= 0; j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),chessAi.getPointX(),j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }

        }
        if(count.getNum() < 2 || flag == 2){
            chessPoints.clear();
        }
        if(count.getNum() == 3){
            chessPoints.forEach(chessPoint -> chessPoint.setDg(2));
        }
        return chessPoints;
    }

    private static void collectMeetHaveDgChess(ChessAi chessAi, int pointX, int PointY) {

    }



    // 1 正常退出，2碰到2个空格退出，3遇到对手棋子退出 4碰到一个空格退出
    private static int dealChessDangerousValue(FiveChess fiveChess, int i, int j, char chessColor,
                                               IntNum space,List<ChessPoint> chessPoints,IntNum count) {
        if (fiveChess.getChess()[i][j] != chessColor) {               
            if(fiveChess.getChess()[i][j] == 32){
                space.add();
                if(space.equals(new IntNum(2))){
                    return 2;
                }
                ChessPoint pr = new ChessPoint(i, j);
                chessPoints.add(pr);
                pr.setDg(1);
                return 4;
            }
            if(fiveChess.getChess()[i][j] == ChessUtil.getOtherColor(chessColor)){
                if(space.equals(new IntNum(1))) {
                    return 4;
                } else {
                    return 3;
                }
            }
        }
        space.setNum(0);
        count.add();
        return 1;
    }

    private static List<ChessPoint> colJudge(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int i = chessAi.getPointX(); i < chessAi.getFiveChess().getHeight(); i++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,chessAi.getPointY(),chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }

        space.setNum(0);
        for (int i = chessAi.getPointX() - 1; i > -1; i--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(), i,chessAi.getPointY(),chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }

        }
        if(count.getNum() < 2 || flag == 2){
            chessPoints.clear();
        }
        if(count.getNum() == 3){
            chessPoints.forEach(chessPoint -> chessPoint.setDg(2));
        }
        return chessPoints;
    }

    // 判断主对角线是否有威胁,并将有威胁的位置标识出来
    private static List<ChessPoint> mainDiagonalJudge(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        int flag = 0;
        // 直连左上角位置，先加入，无威胁去掉
        IntNum space = new IntNum(0);
        for (int i = chessAi.getPointX(), j = chessAi.getPointY(); i < chessAi.getFiveChess().getWidth() && j < chessAi.getFiveChess().getWidth(); i++, j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }

        }
        space.setNum(0);
        for (int i = chessAi.getPointX() - 1, j = chessAi.getPointY() - 1; i >= 0 && j >= 0; i--, j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }

        }
        if(count.getNum() < 2 || flag == 2){
            chessPoints.clear();
        }
        if(count.getNum() == 3){
            chessPoints.forEach(chessPoint -> chessPoint.setDg(2));
        }
        return chessPoints;
    }

    // 判断副对角线是否有威胁,并将有威胁的位置标识出来
    private static List<ChessPoint> deputyDiagonalJudge(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int i = chessAi.getPointX(), j = chessAi.getPointY(); i >= 0 && j < chessAi.getFiveChess().getWidth(); i--, j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }

        }

        space.setNum(0);
        for (int i = chessAi.getPointX() + 1, j = chessAi.getPointY() - 1; i < chessAi.getFiveChess().getHeight() && j >= 0; i++, j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }
        if(count.getNum() < 2 || flag == 2){
            chessPoints.clear();
        }
        if(count.getNum() == 3){
            chessPoints.forEach(chessPoint -> chessPoint.setDg(2));
        }
        return chessPoints;
    }

    private static int rowDg(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int j = chessAi.getPointY(); j <= chessAi.getFiveChess().getWidth() - 1; j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),chessAi.getPointX(),j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2) {
                break;
            }
            if(value == 3) {
                flag++;
                break;
            }
        }

        space.setNum(0);
        for (int j = chessAi.getPointY() - 1; j >= 0; j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),chessAi.getPointX(),j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }

        if(count.getNum() < 2){
            return 0;
        }

        if(count.getNum() == 2) {
            return chessAi.getChessPoint().getDg() + 1 - flag;
        }

        if(count.getNum() == 3){
            return chessAi.getChessPoint().getDg() + chessPoints.size() - flag;
        }
        return 1000;
    }

    private static int colDg(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int i = chessAi.getPointX(); i < chessAi.getFiveChess().getHeight(); i++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,chessAi.getPointY(),chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }

        space.setNum(0);
        for (int i = chessAi.getPointX() - 1; i > -1; i--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,chessAi.getPointY(),chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }
        if(count.getNum() < 3){
            return chessAi.getChessPoint().getDg();
        }
        if(count.getNum() == 3){
            return chessAi.getChessPoint().getDg() + chessPoints.size() - flag;
        }
        return 1000;
    }

    private static int mainDiagonalDg(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        // 直连左上角位置，先加入，无威胁去掉
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int i = chessAi.getPointX(), j = chessAi.getPointY(); i < chessAi.getFiveChess().getWidth() && j < chessAi.getFiveChess().getWidth(); i++, j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }
        space.setNum(0);
        for (int i = chessAi.getPointX() - 1, j = chessAi.getPointY() - 1; i >= 0 && j >= 0; i--, j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }
        if(count.getNum() < 3){
            return 0;
        }
        if(count.getNum() == 3){
            return chessPoints.size() - flag;
        }
        return 1000;
    }

    private static int deputyDiagonalDg(ChessAi chessAi) {
        List<ChessPoint> chessPoints = new ArrayList<>(4);
        IntNum count = new IntNum(0);
        IntNum space = new IntNum(0);
        int flag = 0;
        for (int i = chessAi.getPointX(), j = chessAi.getPointY(); i >= 0 && j < chessAi.getFiveChess().getWidth(); i--, j++) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }

        space.setNum(0);
        for (int i = chessAi.getPointX() + 1, j = chessAi.getPointY() - 1; i < chessAi.getFiveChess().getHeight() && j >= 0; i++, j--) {
            int value = dealChessDangerousValue(chessAi.getFiveChess(),i,j,chessAi.getChessColor(),space,chessPoints,count);
            if(value == 2){
                break;
            }
            if(value == 3){
                flag++;
                break;
            }
        }
        if(count.getNum() < 3){
            return 0;
        }
        if(count.getNum() == 3){
            return chessPoints.size() - flag;
        }
        return 1000;
    }

}
